# _*_coding:utf-8_*_
from ATS.instrumentDriver import InstGen

OK = 0
debug_mode = False


class SMU_2410(InstGen.SMU):
    def __init__(self, name, info_dict):
        InstGen.SMU.__init__(self, name, info_dict)
        self.rangei_list = [0, 1e-6, 10e-6, 100e-6, 1e-3, 20e-3, 1]
        self.rangev_list = [0, 0.2, 2, 20, 1000]
        print(name, info_dict)

    def __universalcom(self, cmdlist, func_id=0):
        """
        func_id: 0="write",1="read",2="ask",3="ask for values"
        """
        rval = None
        if not debug_mode:
            for cmd_str in cmdlist:
                if func_id == 0:
                    self.handler.write(cmd_str)
                elif func_id == 1:
                    rval = self.handler.read()
                elif func_id == 2:
                    rval = self.handler.ask(cmd_str)
                elif func_id == 3:
                    rval = self.handler.ask_for_values(cmd_str)
                elif func_id == 4:
                    rval = self.handler.read_values()
        else:
            for cmd in cmdlist:
                print("\n ", self.name, cmd)
                if func_id == 0:
                    self.handler.write(cmd)
                    if "?" not in cmd:
                        err = self.handler.ask(":syst:err?")
                        print("###error: ", err)
                elif func_id == 1:
                    rval = self.handler.read()
                elif func_id == 2:
                    rval = self.handler.ask(cmd)
                elif func_id == 3:
                    rval = self.handler.ask_for_values(cmd)
                elif func_id == 4:
                    rval = self.handler.read_values()
                print("\t", rval)
        return rval

    def findrangei(self, value):
        if value in self.rangei_list:
            return value
        if value <= 1e-6:
            irange = 1e-6
        elif value <= 10e-6:
            irange = 10e-6
        elif value <= 100e-6:
            irange = 100e-6
        elif value <= 1e-3:
            irange = 1e-3
        elif value <= 20e-3:
            irange = 20e-3
        else:
            irange = 1
        return irange

    def findrangev(self, value):
        if value in self.rangev_list:
            return value
        if value <= 0.2:
            vrange = 0.2
        elif value <= 2:
            vrange = 2
        elif value <= 20:
            vrange = 20
        elif value <= 1000:
            vrange = 1000
        else:
            vrange = 1000
        return vrange

    def reset(self):
        cmd = ["*rst"]
        self.__universalcom(cmd)
        setting = {"beep": 1,
                   "curr_nplc": 1,
                   "volt_nplc": 1,
                   "src_func": 1,  # volt

                   "limiti": 1.05e-4,
                   "limitv": 21,
                   "rangei": 1.05e-4,
                   "rangev": 21,
                   "meas_func": 0,  # curr,1=volt,2=curr+volt
                   "auto_rangei": 1,
                   "lorangei": 1e-6,
                   "auto_rangev": 1,
                   "lorangev": 0.2,
                   "auto_srangei": 1,
                   "srangei": 1e-4,
                   "srangev": 20,
                   "auto_srangev": 1,
                   "rsense": 0,
                   "form_elem": [0, 1, 2, 3, 4],  # 0=curr,1=volt,2=icons,3=time,4=stat
                   "offmode": 1,
                   "src_vmode": 0,  # 0=FIXed, 1=SWEep,2=LIST
                   "src_imode": 0,  # 0=FIXed, 1=SWEep,2=LIST
                   "ilevel": 0,
                   "vlevel": 0,
                   "onoff": 0,
                   }
        self.clearinstsetting()
        self.setinstsetting(setting)
        return OK

    def setbeeper(self, stat):
        setting = self.getinstsetting(["beep"])
        if stat == setting.get("beep", -1):
            return OK
        else:
            cmd = [":SYSTem:BEEPer:STATe %d" % stat]
            self.setinstsetting({"beep": stat})
            self.__universalcom(cmd)
        return OK

    def setnplc(self, nplc, iv_flag):
        func = ["curr", "volt"][iv_flag]
        k = func + "_nplc"
        setting = self.getinstsetting([k])
        if nplc == setting.get(k, -1):
            return OK
        else:
            cmd = [":sens:%s:nplc %g" % (func, nplc)]
            self.setinstsetting({k: nplc})
            self.__universalcom(cmd)
        return OK

    def setoffmode(self, mode):
        """
        mode:
            0 = HIMPedance
            1 = NORMal
            2 = ZERO
            3 = GUARd
        """
        mode_str = ["HIMP", "NORM", "ZERO", "GUAR"]
        setting = self.getinstsetting(["offmode"])
        if mode == setting.get("offmode", -1):
            return OK
        elif mode < 0 or mode >= len(mode_str):
            return OK
        else:
            cmd = [":OUTP:SMOD %s" % mode_str[mode]]
            self.setinstsetting({"offmode": mode})
            self.__universalcom(cmd)
        return OK

    def setremotesense(self, stat):
        setting = self.getinstsetting(["rsense"])
        if stat == setting.get("rsense", -1):
            return OK
        else:
            cmd = [":syst:rsen %d" % stat]
            self.setinstsetting({"rsense": stat})
            self.__universalcom(cmd)
        return OK

    def setsrcfunc(self, mode):
        """
        mode: 0=curr, 1=volt
        """
        setting = self.getinstsetting(["src_func", "onoff"])
        Func_Map = ["curr", "volt"]
        func_str = Func_Map[mode]
        if mode == setting.get("src_func"):
            return OK
        else:
            cmd = [":sour:func:mode %s" % (func_str)]
            setting["src_func"] = mode
            # output will be off if source func changed
            setting["onoff"] = 0
        self.setinstsetting(setting)
        self.__universalcom(cmd)
        return OK

    def outputenable(self, onoff):
        setting = self.getinstsetting(["onoff"])
        cmd = []
        if onoff != setting.get("onoff", -1):  # fixed mode
            cmd.append(":outp %d" % onoff)
            self.setinstsetting({"onoff": onoff})
        self.__universalcom(cmd)
        return OK

    def setlevel(self, val, iv_flag):
        if iv_flag == 1:
            return self.setlevelv(val)
        else:
            return self.setleveli(val)

    def setlevelv(self, v_val):
        setting = self.getinstsetting(["src_vmode", "vlevel"])
        cmd = []
        #        if setting.get("src_vmode",-1)!=0:#fixed mode
        #            cmd.append(":sour:volt:mode fix")
        #            self.setinstsetting({"src_vmode":0})
        if v_val != setting.get("vlevel"):
            cmd.append(":sour:volt %.7g" % v_val)
            self.setinstsetting({"vlevel": v_val})
        self.__universalcom(cmd)
        return OK

    def setleveli(self, i_val):
        setting = self.getinstsetting(["src_imode", "ilevel"])
        cmd = []
        #        if setting.get("src_imode",-1)!=0:#fixed mode
        #            cmd.append(":sour:curr:mode fix")
        #            self.setinstsetting({"src_imode":0})
        if i_val != setting.get("ilevel"):
            cmd.append(":sour:curr %.7g" % i_val)
            self.setinstsetting({"ilevel": i_val})
        self.__universalcom(cmd)
        return OK

    def setmeasfunc(self, func):
        """
        func: 0=curr, 1=volt, 2=curr+volt
        """
        setting = self.getinstsetting(["meas_func"])
        if func == setting.get("meas_func", -1):
            return OK
        else:
            Func_Map = ["\"curr\"", "\"volt\"", "\"curr\",\"volt\""]
            func_str = Func_Map[func]
            cmd = [":sens:func %s" % (func_str)]
            self.setinstsetting({"meas_func": func})
            self.__universalcom(cmd)
        return OK

    def setformelem(self, elem_list):
        elem_list.sort()
        setting = self.getinstsetting(["form_elem"])
        if elem_list == setting.get("form_elem", []):
            return OK
        else:
            Func_Map = ["curr", "volt", "icons", "time", "stat"]
            func_str = [Func_Map[e] for e in elem_list]
            func_str = ",".join(func_str)
            cmd = [":form:elem %s" % (func_str)]
            self.setinstsetting({"form_elem": elem_list})
            self.__universalcom(cmd)
        return OK

    def srcrange(self, rng_val, iv_flag):
        if iv_flag == 1:
            return self.srcrangev(rng_val)
        else:
            return self.srcrangei(rng_val)

    def srcrangei(self, rng_val):
        setting = self.getinstsetting(["auto_srangei", "srangei"])
        # print("srcrangei",setting,rng_val)
        cmd = []
        if rng_val == 0:
            if setting.get("auto_srangei") == 1:
                return OK
            else:
                cmd.append(":sour:curr:rang:auto 1")
                setting["auto_srangei"] = 1
        else:
            if setting.get("auto_srangei") != 0:
                cmd.append(":sour:curr:rang:auto 0")
                setting["auto_srangei"] = 0
            rng_val = self.findrangei(rng_val)
            if rng_val != setting.get("srangei"):
                cmd.append(":sour:curr:rang %g" % rng_val)
                setting["srangei"] = rng_val
        self.setinstsetting(setting)
        self.__universalcom(cmd)
        return OK

    def srcrangev(self, rng_val):
        setting = self.getinstsetting(["auto_srangev", "srangev"])
        cmd = []
        if rng_val == 0:
            if setting.get("auto_srangev") == 1:
                return OK
            else:
                cmd.append(":sour:volt:rang:auto 1")
                setting["auto_srangev"] = 1
        else:
            if setting.get("auto_srangev") != 0:
                cmd.append(":sour:volt:rang:auto 0")
                setting["auto_srangev"] = 0
            rng_val = self.findrangev(rng_val)
            if rng_val != setting.get("srangev"):
                cmd.append(":sour:volt:rang %g" % rng_val)
                setting["srangev"] = rng_val
        self.setinstsetting(setting)
        self.__universalcom(cmd)
        return OK

    def srclorange(self, rng_val, iv_flag):
        if iv_flag == 1:
            return self.srclorangev(rng_val)
        else:
            return self.srclorangei(rng_val)

    def srclorangei(self, rng_val):
        setting = self.getinstsetting(["auto_srangei", "slorangei"])
        cmd = []
        if setting.get("auto_srangei") != 1:
            cmd.append(":sour:curr:rang:auto 1")
            setting["auto_srangei"] = 1
        rng_val = self.findrangei(rng_val)
        if rng_val != setting.get("slorangei"):
            cmd.append(":sour:curr:rang:auto:llim %g" % rng_val)
            setting["slorangei"] = rng_val
        self.setinstsetting(setting)
        self.__universalcom(cmd)
        return OK

    def srclorangev(self, rng_val):
        setting = self.getinstsetting(["auto_srangev", "slorangev"])
        cmd = []
        if setting.get("auto_srangev") != 1:
            cmd.append(":sour:volt:rang:auto 1")
            setting["auto_srangev"] = 1
        rng_val = self.findrangev(rng_val)
        if rng_val != setting.get("slorangev"):
            cmd.append(":sour:volt:rang:auto:llim %g" % rng_val)
            setting["slorangev"] = rng_val
        self.setinstsetting(setting)
        self.__universalcom(cmd)
        return OK

    def range(self, rng_val, iv_flag):
        if iv_flag == 0:
            return self.rangei(rng_val)
        else:
            return self.rangev(rng_val)

    def rangei(self, rng_val):
        setting = self.getinstsetting(["auto_rangei", "rangei"])
        cmd = []
        if rng_val == 0:
            if setting.get("auto_rangei") == 1:
                return OK
            else:
                cmd.append(":sens:curr:rang:auto 1")
                setting["auto_rangei"] = 1
        else:
            if setting.get("auto_rangei") != 0:
                cmd.append(":sens:curr:rang:auto 0")
                setting["auto_rangei"] = 0
            rng_val = self.findrangei(rng_val)
            if rng_val != setting.get("rangei"):
                cmd.append(":sens:curr:rang %g" % rng_val)
                setting["rangei"] = rng_val
        self.setinstsetting(setting)
        self.__universalcom(cmd)
        return OK

    def rangev(self, rng_val):
        setting = self.getinstsetting(["auto_rangev", "rangev"])
        cmd = []
        if rng_val == 0:
            if setting.get("auto_rangev") == 1:
                return OK
            else:
                cmd.append(":sens:volt:rang:auto 1")
                setting["auto_rangev"] = 1
        else:
            if setting.get("auto_rangev") != 0:
                cmd.append(":sens:volt:rang:auto 0")
                setting["auto_rangev"] = 0
            rng_val = self.findrangev(rng_val)
            if rng_val != setting.get("rangev"):
                cmd.append(":sens:volt:rang %g" % rng_val)
                setting["rangev"] = rng_val
        self.setinstsetting(setting)
        self.__universalcom(cmd)
        return OK

    def lorange(self, rng_val, iv_flag):
        if iv_flag == 0:
            return self.lorangei(rng_val)
        else:
            return self.lorangev(rng_val)

    def lorangei(self, rng_val):
        setting = self.getinstsetting(["auto_rangei", "lorangei"])
        cmd = []
        if setting.get("auto_rangei") != 1:
            cmd.append(":sens:curr:rang:auto 1")
            setting["auto_rangei"] = 1
        rng_val = self.findrangei(rng_val)
        if rng_val != setting.get("lorangei"):
            cmd.append(":sens:curr:rang:auto:llim %g" % rng_val)
            setting["lorangei"] = rng_val
        self.setinstsetting(setting)
        self.__universalcom(cmd)
        return OK

    def lorangev(self, rng_val):
        setting = self.getinstsetting(["auto_rangev", "lorangev"])
        cmd = []
        if setting.get("auto_rangev") != 1:
            cmd.append(":sens:volt:rang:auto 1")
            setting["auto_rangev"] = 1
        rng_val = self.findrangev(rng_val)
        if rng_val != setting.get("lorangev"):
            cmd.append(":sens:volt:rang:auto:llim %g" % rng_val)
            setting["lorangev"] = rng_val
        self.setinstsetting(setting)
        self.__universalcom(cmd)
        return OK

    def limit(self, val, iv_flag):
        if iv_flag == 0:
            return self.limiti(val)
        else:
            return self.limitv(val)

    def limiti(self, val):
        setting = self.getinstsetting(["limiti"])
        if val == setting.get("limiti"):
            return OK
        else:
            cmd = [":sens:curr:prot %g" % val]
            self.setinstsetting({"limiti": val})
            self.__universalcom(cmd)
        return OK

    def limitv(self, val):
        setting = self.getinstsetting(["limitv"])
        if val == setting.get("limitv"):
            return OK
        else:
            cmd = [":sens:volt:prot %g" % val]
            self.setinstsetting({"limitv": val})
            self.__universalcom(cmd)
        return OK
